(function () {
    CodeMirror.simpleHint = function (editor, getHints) {
        // We want a single cursor position.
        if (editor.somethingSelected()) return;
        //don't show completion if the token is empty
        var tempToken = editor.getTokenAt(editor.getCursor());
        if (!(/[\S]/gi.test(tempToken.string))) return;

        var result = getHints(editor);
        if (!result || !result.list.length) return;
        var completions = result.list;
        function insert(str) {
            editor.replaceRange(str, result.from, result.to);
        }
        // When there is only one completion, use it directly.
        if (completions.length == 1) { insert(completions[0]); return true; }

        // Build the select widget
        var complete = document.createElement("div");
        complete.className = "CodeMirror-completions";
        var sel = complete.appendChild(document.createElement("select"));
        // Opera doesn't move the selection when pressing up/down in a
        // multi-select, but it does properly support the size property on
        // single-selects, so no multi-select is necessary.
        if (!window.opera) sel.multiple = true;

        for (var i = 0; i < completions.length; ++i) {
            var opt = sel.appendChild(document.createElement("option"));
            var completion = completions[i];

            if (typeof completion === 'object') {
                opt.appendChild(document.createTextNode(completion[0]));
                opt.setAttribute("value", completion[1]);
            }
            else if(typeof completion === 'string') {
                opt.appendChild(document.createTextNode(completion));
                opt.setAttribute("value", completion);
            }
        }
        sel.firstChild.selected = true;
        sel.size = Math.min(10, completions.length);
        var pos = editor.cursorCoords();
        complete.style.left = pos.x + "px";
        complete.style.top = pos.yBot + "px";
        document.body.appendChild(complete);
        // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
        var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
        if (winW - pos.x < sel.clientWidth)
            complete.style.left = (pos.x - sel.clientWidth) + "px";
        // Hack to hide the scrollbar.
        if (completions.length <= 10)
            complete.style.width = (sel.clientWidth - 1) + "px";

        var done = false;
        function close() {
            if (done) return;
            done = true;
            complete.parentNode.removeChild(complete);
        }
        function pick() {
            insert(completions[sel.selectedIndex][1]);
            close();
            setTimeout(function () { editor.focus(); }, 50);
        }
        CodeMirror.connect(sel, "blur", close);
        CodeMirror.connect(sel, "keydown", function (event) {
            var code = event.keyCode;
            // Enter
            if (code == 13) { CodeMirror.e_stop(event); pick(); }
            // Escape
            else if (code == 27) { CodeMirror.e_stop(event); close(); editor.focus(); }
            else if (code != 38 && code != 40) {
                close(); editor.focus();
                // Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
                editor.triggerOnKeyDown(event);
                setTimeout(function () { CodeMirror.simpleHint(editor, getHints); }, 50);
            }
        });
        CodeMirror.connect(sel, "dblclick", pick);

        sel.focus();
        // Opera sometimes ignores focusing a freshly created node
        if (window.opera) setTimeout(function () { if (!done) sel.focus(); }, 100);
        return true;
    };
})();
